package com.kin207.netty.relay.mqtt.listener;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.kin207.netty.context.RequestContext;
import com.kin207.netty.handle.IMessageHandle;
import com.kin207.netty.listener.ListenerConfig;
import com.kin207.netty.listener.MessageHandleListener;
import com.kin207.netty.relay.mqtt.Enum.ClientDataEnum;
import com.kin207.netty.util.StringParseUtils;

public class MqttMessageListener implements MessageHandleListener {
	final static Logger logger = LoggerFactory.getLogger(MqttMessageListener.class);

	private String clientId;
	private String relayQuauaName;
	private String[] relayQuauaNames;
	private String serverURI;
	private Set<String> messageHandleFilterNames;
	private int qos = 0;
	private boolean retained;
	private MqttClient mqttClient;
	private String serviceType;
	private String[] serviceTypes;
	private String[] miniTypes;
	private String startService;
	private String callbackSrevice;
	private String featureService;
	private String generalService;
	private String fingerService;

	private String startWith = "68";
	private String endWith = "0016";
	private Integer indexLength = 1;
	private Integer sendTypeLength = 1;
	private Integer deviceTypeLength = 1;
	private Integer deviceIdLength = 4;
	private Integer randomLength = 2;
	private Integer serviceTypelength = 2;
	private Integer timestampLength = 4;
	private Integer countLength = 2;
	private Integer flagLength = 1;
	private Integer dataLength = 1;
	private Integer multipleLength = 2;
	public String fm226Success = "E7";
	public String fm226Callback = "E8";
	public String fm226AddIn = "E9";
	private String miniType = "47,49,F1,F3,F5,F7,ED,EF,FB,FC,FE,70,71,72,73,74,4B,4D";
	// 47:openlock,49:updateIp,F1:password,F3:delpwd,F5:card,F7:delcard,ED:delFinger,EF:delFaces,FB指锟狡回革拷锟斤拷锟斤拷锟斤拷0020,FB锟斤拷锟斤拷锟截革拷锟斤拷锟斤拷锟斤拷0021
	private String openlock = "47";
	private String updateIp = "49";
	private String password = "F1";
	private String delpwd = "F3";
	private String card = "F5";
	private String delcard = "F7";
	private String delFinger = "ED";
	private String delFaces = "EF";
	private String addFaces = "FB";
	private String goAdd = "FC";
	private String goAddF = "E1";
	public String fail = "FE";
	public String general = "70";
	public String generalSigle = "71";
	public String generalFlag = "72";
	public String generalOpen = "73";
	public String warn = "74";
	private Map<String, String> queueMap = new HashMap<String, String>();

	public void initialize(ListenerConfig cfg) {
		StringParseUtils spu = new StringParseUtils();
		if (!spu.set(cfg.getParam("clientId")).isEmpty()) {
			clientId = spu.get();
			logger.info("set clientId:{}.", clientId);
		}

		if (!spu.set(cfg.getParam("relayQuauaName")).isEmpty()) {
			relayQuauaName = spu.get();
			logger.info("set relayQuauaName:{}.", relayQuauaName);
		}

		relayQuauaNames = relayQuauaName.split(",");
		for (int i = 0; i < relayQuauaNames.length; i++) {
			String key = relayQuauaNames[i].trim().substring(relayQuauaNames[i].lastIndexOf(".") + 1,
					relayQuauaNames[i].length());
			queueMap.put(key, relayQuauaNames[i].trim());
		}

		if (!spu.set(cfg.getParam("serverURI")).isEmpty()) {
			serverURI = spu.get();
			logger.info("set serverURI:{}.", serverURI);
		}

		if (!spu.set(cfg.getParam("retained")).isEmpty()) {
			retained = spu.get().equals("true");
			logger.info("set retained:{}.", retained);
		}
		if (!spu.set(cfg.getParam("msgstart")).isEmpty()) {
			startWith = spu.get();
			logger.info("set startWith:{}.", startWith);
		}
		if (!spu.set(cfg.getParam("msgend")).isEmpty()) {
			endWith = spu.get();
			logger.info("set endWith:{}.", endWith);
		}
		if (!spu.set(cfg.getParam("serviceType")).isEmpty()) {
			serviceType = spu.get();
			serviceTypes = serviceType.split(",");
			startService = serviceTypes[0];
			callbackSrevice = serviceTypes[1];
			generalService = serviceTypes[2];
			fingerService = serviceTypes[3];
			featureService = serviceTypes[4];
		}

		if (!spu.set(cfg.getParam("miniType")).isEmpty()) {
			miniType = spu.get();
			miniTypes = miniType.split(",");
			openlock = miniTypes[0];
			updateIp = miniTypes[1];
			password = miniTypes[2];
			delpwd = miniTypes[3];
			card = miniTypes[4];
			delcard = miniTypes[5];
			delFinger = miniTypes[6];
			delFaces = miniTypes[7];
			addFaces = miniTypes[8];
			goAdd = miniTypes[9];
			fail = miniTypes[10];
			general = miniTypes[11];
			generalSigle = miniTypes[12];
			generalFlag = miniTypes[13];
			generalOpen = miniTypes[14];
			warn = miniTypes[15];
		}

		if (!spu.set(cfg.getParam("messageHandleFilterNames")).isEmpty()) {
			messageHandleFilterNames = new HashSet();
			String[] ss = spu.split(",");
			for (String item : ss) {
				messageHandleFilterNames.add(item.trim());
				logger.info("add messageHandleFilterNames:{}", item);
			}
		} else {
			logger.info("messageHandleFilterNames is empty.");
		}

		MqttConnectOptions mqcConf = new MqttConnectOptions();
		if (!spu.set(cfg.getParam("options")).isEmpty()) {
			String options = spu.get();
			mqcConf = JSONObject.parseObject(options, MqttConnectOptions.class);
		}

		if (!spu.set(cfg.getParam("messagelength")).isEmpty()) {
			String messagelength = spu.get();
			JSONObject messagelengths = JSONObject.parseObject(messagelength);
			logger.debug("JSONObject messagelengths:" + messagelengths.toJSONString());
			if (messagelengths.get("indexLength") != null) {
				indexLength = Integer.valueOf(messagelengths.get("indexLength").toString().trim());
			}
			if (messagelengths.get("sendTypeLength") != null) {
				sendTypeLength = Integer.valueOf(messagelengths.get("sendTypeLength").toString().trim());
			}
			if (messagelengths.get("deviceTypeLength deviceIdLength") != null) {
				deviceTypeLength = Integer.valueOf(messagelengths.get("deviceTypeLength").toString().trim());
			}
			if (messagelengths.get("deviceIdLength") != null) {
				deviceIdLength = Integer.valueOf(messagelengths.get("deviceIdLength").toString());
			}
			if (messagelengths.get("randomLength") != null) {
				randomLength = Integer.valueOf(messagelengths.get("randomLength").toString().trim());
			}
			if (messagelengths.get("serviceTypeLength") != null) {
				serviceTypelength = Integer.valueOf(messagelengths.get("serviceTypeLength").toString().trim());
			}
			if (messagelengths.get("timestampLength") != null) {
				timestampLength = Integer.valueOf(messagelengths.get("timestampLength").toString().trim());
			}
			if (messagelengths.get("countLength") != null) {
				countLength = Integer.valueOf(messagelengths.get("countLength").toString().trim());
			}
			if (messagelengths.get("flagLength") != null) {
				flagLength = Integer.valueOf(messagelengths.get("flagLength").toString().trim());
			}
			if (messagelengths.get("dataLength") != null) {
				dataLength = Integer.valueOf(messagelengths.get("dataLength").toString().trim());
			}
			if (messagelengths.get("multipleLength") != null) {
				multipleLength = Integer.valueOf(messagelengths.get("multipleLength").toString().trim());
			}
		}

		try {
			logger.info("open mqtt connection, options:{}", mqcConf, new MemoryPersistence());
			mqttClient = new MqttClient(serverURI, clientId);
			mqttClient.connect(mqcConf);
			logger.info("open mqtt connection success.");
		} catch (MqttException e) {
			logger.error(e.getMessage(), e);
		}
	}

	public void created(IMessageHandle t) {
		RequestContext req = RequestContext.curr.get();
		final String msg = req.getMessage();
		final String clientId = req.getSession().getId();
		final String serverId = req.getServer().getName();
		final String clientName = req.getSession().getName();
		if (this.getServiceType(msg).equals(startService)) { // 0006上线取数据
			publish(serverId, clientId, clientName, queueMap.get(ClientDataEnum.START.getName()), msg, null);
			logger.error("post START send relay mqtt queueName:{},  sid:{}, cid:{}, clientName:{}, message:{}",
					queueMap.get(ClientDataEnum.START.getName()), serverId, clientId, clientName, msg);
		} else if (this.getServiceType(msg).equals(callbackSrevice)// 0021添加人脸取人脸数据
				&& this.getFlag(msg).equalsIgnoreCase(addFaces)) {
			publish(serverId, clientId, clientName, queueMap.get(ClientDataEnum.SUCCESS.getName()), msg, null);
			logger.error("ping SUCCESS send relay mqtt queueName:{},  sid:{}, cid:{}, clientName:{}, message:{}",
					ClientDataEnum.SUCCESS.getName(), serverId, clientId, clientName, msg, this.getFlag(msg));
		} else if (this.getFlag(msg).equalsIgnoreCase(fm226AddIn)) {
			logger.error("created msg plush:" + msg + "queueMap.get(ClientDataEnum.FM226.getName():"
					+ queueMap.get(ClientDataEnum.FM226.getName()));
			publish(serverId, clientId, clientName, queueMap.get(ClientDataEnum.FM226.getName()), msg,
					this.getFlag(msg));
		} if (this.getFlag(msg).equalsIgnoreCase(fm226Success)) {
			logger.error("created msg plush:"+msg+"queueMap.get(ClientDataEnum.FM226.getName():"+queueMap.get(ClientDataEnum.FM226.getName()));
			publish(serverId, clientId, clientName, queueMap.get(ClientDataEnum.SUCCESS.getName()), msg,
					this.getFlag(msg));
		}else if (this.getServiceType(msg).equals(callbackSrevice)
				&& (this.getFlag(msg).equalsIgnoreCase(fail) || this.getFlag(msg).equalsIgnoreCase(goAdd))) {// 0021添加人脸数据返回成功或者失败
			publish(serverId, clientId, clientName, queueMap.get(ClientDataEnum.CALLBACK.getName()), msg, null);
			logger.error("ping SUCCESS send relay mqtt queueName:{},  sid:{}, cid:{}, clientName:{}, message:{}",
					ClientDataEnum.CALLBACK.getName(), serverId, clientId, clientName, msg);
		} else if (this.getServiceType(msg).equals(featureService)
				&& (this.getFlag(msg).equalsIgnoreCase(fail) || this.getFlag(msg).equalsIgnoreCase(goAddF))) {// 0022添加人脸数据返回成功或者失败
			publish(serverId, clientId, clientName, queueMap.get(ClientDataEnum.SUCCESS.getName()), msg, null);
			logger.error("ping SUCCESS send relay mqtt queueName:{},  sid:{}, cid:{}, clientName:{}, message:{}",
					ClientDataEnum.SUCCESS.getName(), serverId, clientId, clientName, msg);
		} else if (this.getServiceType(msg).equals(generalService)// 0001添加或者删除密码普通回复
				&& (this.getFlag(msg).equalsIgnoreCase(password) || this.getFlag(msg).equalsIgnoreCase(delpwd))) {
			publish(serverId, clientId, clientName, queueMap.get(ClientDataEnum.PASSWORD.getName()), msg,
					this.getFlag(msg));
			logger.error(
					"ping generalService password/delpwd send relay mqtt queueName:{},  sid:{}, cid:{}, clientName:{}, message:{}",
					ClientDataEnum.PASSWORD.getName(), serverId, clientId, clientName, msg);
		} else if (this.getServiceType(msg).equals(generalService)// 0001添加或者删除卡片普通回复
				&& (this.getFlag(msg).equalsIgnoreCase(card) || this.getFlag(msg).equalsIgnoreCase(delcard))) {
			publish(serverId, clientId, clientName, queueMap.get(ClientDataEnum.CARD.getName()), msg,
					this.getFlag(msg));
			logger.error(
					"ping generalService card/delcard send relay mqtt queueName:{},  sid:{}, cid:{}, clientName:{}, message:{}",
					ClientDataEnum.CARD.getName(), serverId, clientId, clientName, msg);
		} else if (this.getServiceType(msg).equals(generalService)// 0001删除指纹普通回复
				&& this.getFlag(msg).equalsIgnoreCase(delFinger)) {
			publish(serverId, clientId, clientName, queueMap.get(ClientDataEnum.FINGER.getName()), msg, null);
			logger.error(
					"ping generalService delFinger send relay mqtt queueName:{},  sid:{}, cid:{}, clientName:{}, message:{}",
					ClientDataEnum.FINGER.getName(), serverId, clientId, clientName, msg);
		} else if (this.getServiceType(msg).equals(generalService)// 0001删除人脸普通回复
				&& this.getFlag(msg).equalsIgnoreCase(delFaces)) {

			publish(serverId, clientId, clientName, queueMap.get(ClientDataEnum.DELIMAGE.getName()), msg, null);
			logger.error(
					"ping generalService delFaces send relay mqtt queueName:{},  sid:{}, cid:{}, clientName:{}, message:{}",
					ClientDataEnum.DELIMAGE.getName(), serverId, clientId, clientName, msg);
		} else if (this.getServiceType(msg).equals(generalService)// 0001普通回复开锁/修改IP(作为日志)
				&& (this.getFlag(msg).equalsIgnoreCase(openlock) || this.getFlag(msg).equalsIgnoreCase(updateIp))) {
			publish(serverId, clientId, clientName, queueMap.get(ClientDataEnum.GENERAL.getName()), msg,
					this.getFlag(msg));
			logger.error(
					"ping generalService openlock/updateIp send relay mqtt queueName:{},  sid:{}, cid:{}, clientName:{}, message:{}",
					ClientDataEnum.GENERAL.getName(), serverId, clientId, clientName, msg);
		} else if (this.getServiceType(msg).equals(generalService)// 0001第二包上报电量 遇到70,71,72,73,74的信息上报
				&& (this.getFlag(msg).equalsIgnoreCase(general) || this.getFlag(msg).equalsIgnoreCase(generalSigle)
						|| this.getFlag(msg).equalsIgnoreCase(generalFlag)
						|| this.getFlag(msg).equalsIgnoreCase(generalOpen)
						|| this.getFlag(msg).equalsIgnoreCase(warn))) {
			publish(serverId, clientId, clientName, queueMap.get(ClientDataEnum.REPORT.getName()), msg,
					this.getFlag(msg));
			logger.error(
					"ping generalService report/openLock send relay mqtt queueName:{},  sid:{}, cid:{}, clientName:{}, message:{}",
					ClientDataEnum.GENERAL.getName(), serverId, clientId, clientName, msg);
		} else if (this.getServiceType(msg).equals(fingerService)) {// 0020添加指纹返回
			publish(serverId, clientId, clientName, queueMap.get(ClientDataEnum.FINGER.getName()), msg,
					this.getFlag(msg));
			logger.error(
					"ping fingerService delFinger send relay mqtt queueName:{},  sid:{}, cid:{}, clientName:{}, message:{}",
					ClientDataEnum.FINGER.getName(), serverId, clientId, clientName, msg);
		} else {
			publish(serverId, clientId, clientName, queueMap.get(ClientDataEnum.OTHER.getName()), msg,
					this.getFlag(msg));
			logger.error(
					"ping fingerService delFinger send relay mqtt queueName:{},  sid:{}, cid:{}, clientName:{}, message:{}",
					ClientDataEnum.FINGER.getName(), serverId, clientId, clientName, msg);
		}
		logger.error("send relay mqtt success.");
	}

	public void destroyed(IMessageHandle t) {

	}

	private void publish(String serverId, String clientId, String clientName, String queueName, String msg,
			String type) {
		JSONObject json = new JSONObject();
		json.put("sid", serverId);
		json.put("cid", clientId);
		json.put("name", clientName);
		json.put("sid", serverId);
		json.put("message", msg);
		json.put("type", type);
		MqttMessage mqttMsg = new MqttMessage();
		mqttMsg.setPayload(json.toJSONString().getBytes());
		mqttMsg.setQos(qos);
		mqttMsg.setRetained(retained);
		try {
			mqttClient.publish(queueName, mqttMsg);
		} catch (Exception e) {
			logger.error(e.getMessage(), e);
			throw new RuntimeException(e.getMessage(), e);
		}
	}

	private static String toJson(String handleName, Object param) {
		StringBuffer result = new StringBuffer();
		result.append("{\"handle\":\"").append(handleName).append("\",\"param\":");
		result.append(JSON.toJSONString(param));
		return result.toString();
	}

	private static String toJson(Object param) {
		return JSON.toJSONString(param);
	}

	public String getDeviceId(String msg) {

		if (msg.startsWith(startWith) && msg.endsWith(endWith)) {
			return msg.substring(getBaseLength(), getDeviceIdEnd());
		}
		return "";
	}

	public String getRandom(String msg) {
		if (msg.startsWith(startWith) && msg.endsWith(endWith)) {
			return msg.substring(getDeviceIdEnd(), getRandomEnd());
		}
		return "";
	}

	public String getServiceType(String msg) {
		if (msg.startsWith(startWith) && msg.endsWith(endWith)) {
			return msg.substring(getRandomEnd(), getServiceTypeEnd());
		}
		return "";
	}

	public String getTimestamp(String msg) {
		if (msg.startsWith(startWith) && msg.endsWith(endWith)) {
			return msg.substring(getServiceTypeEnd(), getTimestampEnd());
		}
		return "";
	}

	public Integer getCount(String msg) {
		if (msg.startsWith(startWith + "") && msg.endsWith(endWith + "")) {
			String length = msg.substring(getTimestampEnd(), getCountEnd());
			return Integer.parseInt(length);
		}
		return null;
	}

	public String getFlag(String msg) {
		if (msg.startsWith(startWith) && msg.endsWith(endWith)) {
			return msg.substring(getCountEnd(), getFlagEnd());
		}
		return "";
	}

	public String getData(String msg) {
		if (msg.startsWith(startWith) && msg.endsWith(endWith)) {
			return msg.substring(getDataLengthEnd(), getDataLengthEnd() + getDataLength(msg));
		}
		return "";
	}

	public Integer getBaseLength() {
		return (indexLength + sendTypeLength + deviceTypeLength) * multipleLength;
	}

	public Integer getDeviceIdEnd() {
		return getBaseLength() + deviceIdLength * multipleLength;
	}

	public Integer getRandomEnd() {
		return getDeviceIdEnd() + randomLength * multipleLength;
	}

	public Integer getServiceTypeEnd() {
		return getRandomEnd() + serviceTypelength * multipleLength;
	}

	public Integer getTimestampEnd() {
		return getServiceTypeEnd() + timestampLength * multipleLength;
	}

	public Integer getCountEnd() {
		return getTimestampEnd() + countLength * multipleLength;
	}

	public Integer getFlagEnd() {
		return getCountEnd() + flagLength * multipleLength;
	}

	public Integer getDataLengthEnd() {
		return getFlagEnd() + dataLength * multipleLength;
	}

	public String getCheckResultMessage(String msg) {
		StringBuffer msgbuff = new StringBuffer(msg);
		msgbuff.replace(getRandomEnd(), getServiceTypeEnd(), "0005");
		return msgbuff.toString();
	}

	public Integer getDataLength(String msg) {
		if (msg.startsWith(startWith) && msg.endsWith(endWith)) {
			String length = msg.substring(getFlagEnd(), getDataLengthEnd());
			return Integer.parseInt(length) * multipleLength;
		}
		return null;
	}

	public String getClientId() {
		return clientId;
	}

	public void setClientId(String clientId) {
		this.clientId = clientId;
	}

	public String getRelayQuauaName() {
		return relayQuauaName;
	}

	public void set(String relayQuauaName) {
		this.relayQuauaName = relayQuauaName;
	}

	public String getServerURI() {
		return serverURI;
	}

	public void setServerURI(String serverURI) {
		this.serverURI = serverURI;
	}

	public Set<String> getMessageHandleFilterNames() {
		return messageHandleFilterNames;
	}

	public void setMessageHandleFilterNames(Set<String> messageHandleFilterNames) {
		this.messageHandleFilterNames = messageHandleFilterNames;
	}

	public int getQos() {
		return qos;
	}

	public void setQos(int qos) {
		this.qos = qos;
	}

	public MqttClient getMqttClient() {
		return mqttClient;
	}

	public void setMqttClient(MqttClient mqttClient) {
		this.mqttClient = mqttClient;
	}

	public static void main(String[] args) {
		MqttMessageListener ml = new MqttMessageListener();
		System.out.println("e1".equalsIgnoreCase("E1"));
		System.out.println(ml.getDeviceId("680301FFFFFFFF888800000000000000000016"));
	}
}
